{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# PySDR发送信号初探\n",
    "\n",
    "作者：Jenny\n",
    "\n",
    "时间：2024.5.6\n",
    "\n",
    "参考：\n",
    "1. PlutoSDR in Python https://pysdr.org/content/pluto.html\n",
    "2. ChatGPT4 http://chat.openai.com/\n",
    "3. ADALM-PLUTO Overview https://wiki.analog.com/university/tools/pluto"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 测试连接"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import adi\n",
    "sdr = adi.Pluto('ip:192.168.2.1') # or whatever your Pluto's IP is\n",
    "sdr.sample_rate = int(2.5e6)\n",
    "sdr.rx()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 发送QPSK信号"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import adi\n",
    "import numpy as np\n",
    "\n",
    "# 配置ADALM-Pluto设备\n",
    "sdr = adi.Pluto(\"ip:192.168.2.1\")\n",
    "sdr.sample_rate = int(1e6)\n",
    "sdr.tx_rf_bandwidth = int(50e3)\n",
    "sdr.tx_lo = int(435e6)\n",
    "sdr.tx_hardwaregain_chan0 = -10  # 合理的增益范围\n",
    "sdr.tx_cyclic_buffer = True\n",
    "\n",
    "# 确保发送缓冲区在设备允许范围内\n",
    "sdr.tx_buffer_size = 1024\n",
    "\n",
    "# QPSK信号生成函数\n",
    "def generate_qpsk(num_samples):\n",
    "    bits = np.random.randint(0, 2, num_samples * 2)  # 生成随机比特\n",
    "    symbols = bits[0::2] + 1j * bits[1::2]  # 形成复数符号\n",
    "    return symbols\n",
    "\n",
    "# 生成QPSK信号\n",
    "num_samples = sdr.tx_buffer_size //2\n",
    "qpsk_signal = generate_qpsk(num_samples)\n",
    "\n",
    "# 确保信号幅度符合ADALM-Pluto的范围\n",
    "qpsk_signal *= 2**14\n",
    "\n",
    "# 发送QPSK信号\n",
    "sdr.tx(qpsk_signal)\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 发送FM音频"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import adi\n",
    "import numpy as np\n",
    "from scipy.io import wavfile\n",
    "\n",
    "# 配置ADALM-Pluto设备\n",
    "sdr = adi.Pluto(\"ip:192.168.2.1\")\n",
    "sdr.sample_rate = int(1e6)\n",
    "sdr.tx_rf_bandwidth = int(0.5e3)\n",
    "sdr.tx_lo = int(435e6)\n",
    "sdr.tx_hardwaregain_chan0 = -10  # 合理的增益范围\n",
    "sdr.tx_cyclic_buffer = True  # 设置循环模式\n",
    "\n",
    "# 读取WAV文件并获取前30秒的音频数据\n",
    "sample_rate, audio_data = wavfile.read(\"WildCards.wav\")\n",
    "audio_data = audio_data / 32768.0  # 假设16-bit PCM数据，归一化到[-1, 1]范围\n",
    "seconds_to_send = 30\n",
    "num_samples = sample_rate * seconds_to_send  # 计算前30秒的样本数\n",
    "audio_data = audio_data[:num_samples]  # 只保留前30秒的音频数据\n",
    "\n",
    "# FM调制函数\n",
    "def fm_modulate(audio, deviation, sample_rate):\n",
    "    t = np.arange(len(audio)) / sample_rate\n",
    "    integral = np.cumsum(audio) / sample_rate\n",
    "    return np.exp(2j * np.pi * (deviation * integral))\n",
    "\n",
    "# 使用裁剪后的信号进行发送\n",
    "modulated_signal = fm_modulate(audio_data, 75e3, sample_rate)\n",
    "modulated_signal *= 2**14\n",
    "\n",
    "# 发送FM调制信号\n",
    "sdr.tx(modulated_signal)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 清空缓存区"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "sdr.tx_destroy_buffer()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "pySDR",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.14"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
